﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Xml;

using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Highlighting.Xshd;
using Microsoft.Win32;
using Interpreter;
using ICSharpCode.AvalonEdit.Folding;
using ICSharpCode.AvalonEdit;

namespace LogoScriptIDE
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// 编辑器
    /// </summary>
    public partial class EditorWindow : UserControl
    {
        #region Members and Attributes

        /// <summary>
        /// 计时器
        /// </summary>
        private System.Windows.Threading.DispatcherTimer m_timer;

        /// <summary>
        /// 默认代码
        /// </summary>
        private readonly static string InitialCode
            = "function main() {" + Environment.NewLine
            + "\t`write your code here" + Environment.NewLine + "}" + Environment.NewLine;

        /// <summary>
        /// 当前行高亮器
        /// </summary>
        private CaretLineRenderer m_caretLineRenderer;

        /// <summary>
        /// 代码行高亮器
        /// </summary>
        private CodeLineRenderer m_codeLineRenderer;

        /// <summary>
        /// 堆栈跳转行高亮器（可以合并到代码行高亮器？）
        /// </summary>
        private CodeLineRenderer m_codeStackRenderer;

        /// <summary>
        /// 断点控制边缘（在行号的左边）
        /// </summary>
        private BreakPointMargin m_breakPointMargin;

        /// <summary>
        /// 保存上次修改时间
        /// </summary>
        private DateTime m_lastModifyTime = DateTime.Now;

        /// <summary>
        /// 获取或设置代码
        /// </summary>
        public String Code
        {
            get { return ui_editor.Text; }
            set { ui_editor.Text = value; }
        }

        bool m_modified = false;
        /// <summary>
        /// 获取或设置是否被修改
        /// </summary>
        public bool Modified
        {
            get { return m_modified; }
            private set
            {
                if (m_modified != value)
                {
                    m_modified = value;
                    //若被修改，则刷新标题
                    RefreshTitle();
                }
            }
        }

        /// <summary>
        /// 获取或设置是否允许修改
        /// </summary>
        public bool Locked
        {
            get
            {
                return ui_editor.IsReadOnly;
            }
            set
            {
                ui_editor.IsReadOnly = value;
            }
        }

        /// <summary>
        /// 暂停行颜色
        /// </summary>
        private Color m_pauseColor = Color.FromArgb(0x40, 0xFF, 0xFF, 0);

        /// <summary>
        /// 获取或设置暂停行
        /// </summary>
        public int PauseLine
        {
            get
            {
                return m_breakPointMargin.PausingLineNumber;
            }
            set
            {
                if (!m_initialized) return;
                if (value != -1) m_errorLine = -1;
                // 若暂停行存在，则需要对该行进行高亮处理
                m_breakPointMargin.PausingLineNumber = value;
                m_codeLineRenderer.RenderSettings.Clear();
                if (value > 0)
                {
                    var setting = new CodeLineRenderer.Setting(value, m_pauseColor);
                    m_codeLineRenderer.RenderSettings.Add(setting);
                }
                // 重绘
                ui_editor.TextArea.TextView.InvalidateLayer(m_codeLineRenderer.Layer);
            }
        }

        /// <summary>
        /// 堆栈跳转行颜色
        /// </summary>
        private Color m_stackColor = Color.FromArgb(50, 0x00, 0xFF, 0x00);

        private int m_stackLine;
        /// <summary>
        /// 获取或设置堆栈跳转行
        /// </summary>
        public void StackCallLine(int line)
        {
            m_stackLine = line;
            if (m_codeStackRenderer != null)
            {
                m_codeStackRenderer.RenderSettings.Clear();

                // 该行存在，则需要对该行进行高亮处理
                if (line > 0)
                {
                    var setting = new CodeLineRenderer.Setting(line, m_stackColor);
                    m_codeStackRenderer.RenderSettings.Add(setting);
                    // 重绘
                    ui_editor.TextArea.TextView.InvalidateLayer(m_codeStackRenderer.Layer);
                }
            }
        }

        /// <summary>
        /// 错误行行号
        /// </summary>
        private int m_errorLine = -1;

        /// <summary>
        /// 错误行颜色
        /// </summary>
        private Color m_errorColor = Color.FromArgb(0x40, 0xFF, 0, 0);

        /// <summary>
        /// 获取或设置错误行行号
        /// </summary>
        public int ErrorLine
        {
            get { return m_errorLine; }
            set
            {
                if (!m_initialized) return;
                if (value != -1) m_breakPointMargin.PausingLineNumber = -1;
                m_errorLine = value;

                //高亮错误行
                m_codeLineRenderer.RenderSettings.Clear();
                if (value > 0)
                {
                    var setting = new CodeLineRenderer.Setting(value, m_errorColor);
                    m_codeLineRenderer.RenderSettings.Add(setting);
                }

                //重绘
                ui_editor.TextArea.TextView.InvalidateLayer(m_codeLineRenderer.Layer);
            }
        }

        /// <summary>
        /// 获取或设置断点列表
        /// </summary>
        public ICollection<int> BreakPoints
        {
            get
            {
                List<int> lineNumbers = new List<int>();
                m_breakPointMargin.GetBreakPoints(lineNumbers);
                return lineNumbers;
            }
            set
            {
                //若将断点列表设置为空，则清空所有断点
                if (value == null)
                    m_breakPointMargin.ClearBreakPoints();
                else
                    m_breakPointMargin.SetBreakPoints(value);
            }
        }

        /// <summary>
        /// 文件名
        /// </summary>
        private string m_fileName = "Unnamed";

        /// <summary>
        /// 获取或设置文件名
        /// </summary>
        public string FileName
        {
            get { return m_fileName; }
            private set
            {
                m_fileName = value; 
                // 刷新标题
                RefreshTitle();
            }
        }

        /// <summary>
        /// 保存的文件路径，若不存在则为空字符串
        /// </summary>
        private string m_filePath = "";

        /// <summary>
        /// 获取保存的文件路径
        /// </summary>
        public string FilePath
        {
            get { return m_filePath; }
            private set { m_filePath = value; }
        }

        #endregion

        #region Initialization

        /// <summary>
        /// 构造函数
        /// </summary>
        public EditorWindow()
        {
            InitializeComponent();
            m_keyfunctions = new HashSet<string>();
        }

        /// <summary>
        /// 保存是否已完成初始化
        /// </summary>
        private bool m_initialized = false;

        /// <summary>
        /// 获取或设置默认文件路径
        /// </summary>
        public string InitialPath { get; set; }

        /// <summary>
        /// 获取或设置默认文件名
        /// </summary>
        public string InitialName { get; set; }

        /// <summary>
        /// 对应的配置文件名
        /// </summary>
        static private readonly string ConfigPath = AppDomain.CurrentDomain.BaseDirectory + "editor_config.cfg";

        private HashSet<string> m_keyfunctions;
        /// <summary>
        /// 获取或设置系统函数
        /// </summary>
        public HashSet<string> KeyFunctions
        {
            get { return m_keyfunctions; }
            set { m_keyfunctions = value; }
        }

        /// <summary>
        /// 载入完成回调函数
        /// </summary>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                // 新建窗口部件
                m_breakPointMargin = new BreakPointMargin(ui_editor);
                ui_editor.TextArea.LeftMargins.Insert(0, m_breakPointMargin);

                m_codeLineRenderer = new CodeLineRenderer(ui_editor);
                ui_editor.TextArea.TextView.BackgroundRenderers.Add(m_codeLineRenderer);

                m_codeStackRenderer = new CodeLineRenderer(ui_editor);
                ui_editor.TextArea.TextView.BackgroundRenderers.Add(m_codeStackRenderer);

                m_caretLineRenderer = new CaretLineRenderer(ui_editor);
                ui_editor.TextArea.TextView.BackgroundRenderers.Add(m_caretLineRenderer);
                ui_editor.Text = InitialCode;

                try
                {
                    // 载入配置信息
                    using (StreamReader sr = new StreamReader(ConfigPath))
                        Configure.Load(sr);
                }
                catch
                {
                    // 若载入失败则使用默认配置
                    Configure = new Config();
                }

                // 设定系统函数
                Configure.KeyFunctions = KeyFunctions;

                // 根据配置更新界面
                UpdateConfig();

                Modified = false;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            
            try
            {
                // 尝试从初始路径载入代码
                FilePath = InitialPath;
                FileName = InitialName;
                ui_editor.Load(FilePath);
            }
            catch
            {
                // 若载入失败则显示默认初始代码
                FilePath = "";
                FileName = "Unnamed";
                Code = InitialCode;
            }
            // 代码区域尚未被编辑过
            Modified = false;

            // 设置计时器
            m_timer = new System.Windows.Threading.DispatcherTimer(
                System.Windows.Threading.DispatcherPriority.Send);
            m_timer.Tick += new EventHandler(TimerTick);
            m_timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
            m_timer.Start();

            // 新建代码折叠策略，并加入到代码折叠管理器中
            foldingStrategy = new FoldingStrategy();
            foldingManager = FoldingManager.Install(ui_editor.TextArea);

            m_initialized = true;
        }

        #endregion

        #region Edit Commands

        /// <summary>
        /// 撤销上次操作
        /// </summary>
        public void Undo()
        {
            ui_editor.Undo();
        }

        /// <summary>
        /// 重做上次撤销的操作
        /// </summary>
        public void Redo()
        {
            ui_editor.Redo();
        }

        /// <summary>
        /// 剪切所选的代码段
        /// </summary>
        public void Cut()
        {
            if (ui_editor.SelectionLength > 0)
                ui_editor.Cut();
        }

        /// <summary>
        /// 复制所选的代码段
        /// </summary>
        public void Copy()
        {
            if (ui_editor.SelectionLength > 0)
                ui_editor.Copy();
        }

        /// <summary>
        /// 在当前光标处粘贴
        /// </summary>
        public void Paste()
        {
            ui_editor.Paste();
        }

        /// <summary>
        /// 在当前光标处插入代码
        /// </summary>
        /// <param name="text">代码</param>
        public void InsertText(string text)
        {
            // 只读情况下拒绝插入
            if (ui_editor.IsReadOnly)
                return;

            // 获取光标所在行
            var line = ui_editor.Document.GetLineByOffset(ui_editor.CaretOffset);
            string newLine = Environment.NewLine;

            // 自动缩进
            for (int i = line.Offset; i < ui_editor.CaretOffset; ++i)
            {
                char c = ui_editor.Document.GetCharAt(i);
                if (Char.IsWhiteSpace(c))
                {
                    if (c != '\r' && c != '\n')
                        newLine += c;
                }
                else
                {
                    break;
                }
            }

            // 插入代码
            ui_editor.Document.Insert(ui_editor.CaretOffset, text + newLine);
        }

        /// <summary>
        /// 注释选中行
        /// </summary>
        public void Comment()
        {
            if (ui_editor.IsReadOnly)
                return;

            // 计算起始行行号，计算终止行行号
            int startCaretIndex = ui_editor.SelectionStart;
            int endCaretIndex = startCaretIndex + ui_editor.SelectionLength;
            int startLineNum = ui_editor.Document.GetLineByOffset(startCaretIndex).LineNumber;
            int endLineNum = ui_editor.Document.GetLineByOffset(endCaretIndex).LineNumber;

            // 开始整段操作（撤销时可以一步撤销）
            ui_editor.BeginChange();
            for (int i = startLineNum; i <= endLineNum; ++i)
            {
                // 获取当前行
                var line = ui_editor.Document.GetLineByNumber(i);
                int startOffset = line.Offset;
                int endOffset = line.EndOffset;

                // 判断该行是否为空
                bool isEmpty = true;
                int j = startOffset;
                for (/*empty*/; j < endOffset; ++j)
                {
                    if (!Char.IsWhiteSpace(ui_editor.Document.GetCharAt(j)))
                    {
                        isEmpty = false;
                        break;
                    }
                }

                // 对于空行，不插入注释符
                if (!isEmpty)
                {
                    ui_editor.Document.Insert(j, "`");
                }
            }
            ui_editor.EndChange();
        }

        /// <summary>
        /// 取消注释选中行
        /// </summary>
        public void Uncomment()
        {
            if (ui_editor.IsReadOnly)
                return;

            // 计算起始行行号，计算终止行行号
            int startCaretIndex = ui_editor.SelectionStart;
            int endCaretIndex = startCaretIndex + ui_editor.SelectionLength;
            int startLineNum = ui_editor.Document.GetLineByOffset(startCaretIndex).LineNumber;
            int endLineNum = ui_editor.Document.GetLineByOffset(endCaretIndex).LineNumber;

            // 开始整段操作（撤销时可以一步撤销）
            ui_editor.BeginChange();
            for (int i = startLineNum; i <= endLineNum; ++i)
            {
                var line = ui_editor.Document.GetLineByNumber(i);
                int startOffset = line.Offset;
                int endOffset = line.EndOffset;

                // 判断该行的第一个字符是否为注释符，并获取它的位置
                bool meetComment = false;
                int j = startOffset;
                for (/*empt*/; j < endOffset; ++j)
                {
                    if (ui_editor.Document.GetCharAt(j) == '`')
                    {
                        meetComment = true;
                        break;
                    }
                }

                // 只有当该行第一个字符是注释符的时候，才删除它
                if (meetComment)
                {
                    ui_editor.Document.Remove(j, 1);
                }
            }
            ui_editor.EndChange();
        }

        /// <summary>
        /// 删除所有断点
        /// </summary>
        public void RemoveBreakpoints()
        {
            // 清空所有断点
            m_breakPointMargin.ClearBreakPoints();
            // 重绘
            m_breakPointMargin.InvalidateVisual();
        }

        #endregion

        #region Events

        /// <summary>
        /// 代码改变回调函数
        /// </summary>
        private void ui_editor_TextChanged(object sender, EventArgs e)
        {
            // 标记代码为已修改
            Modified = true;
            m_lastModifyTime = DateTime.Now;
            ErrorLine = -1;
        }

        #endregion

        #region File Commands

        public static RoutedCommand CommandOpen = new RoutedCommand();
        public static RoutedCommand CommandSave = new RoutedCommand();
        public static RoutedCommand CommandNew = new RoutedCommand();

        /// <summary>
        /// 刷新标题
        /// </summary>
        private void RefreshTitle()
        {
            //如果已修改，则在标题文件名处插入星号
            string s = Modified ? "* " : "";
            ((Parent as Grid).Parent as MainWindow).Title = "LogoScript IDE - " + FileName + s;
        }

        /// <summary>
        /// 判断文件是否已更改，若已更改则提示保存
        /// </summary>
        /// <param name="noAllowed">是否允许用户拒绝保存</param>
        /// <returns>返回用户是否保存成功</returns>
        public bool CheckModifiedCode(bool noAllowed)
        {
            if (Modified)
            {
                // 提示用户是否需要保存代码
                MessageBoxResult result =
                    MessageBox.Show("Save File " + FileName + "?", "Save",
                    noAllowed ? MessageBoxButton.YesNoCancel : MessageBoxButton.OKCancel);

                if (result == MessageBoxResult.Cancel)
                    return false;

                // 若用户选择保存，则保存代码
                if (result == MessageBoxResult.Yes ||
                    result == MessageBoxResult.OK)
                    return Save();
            }
            return true;
        }

        /// <summary>
        /// 新建代码
        /// </summary>
        public void New()
        {
            // 如果当前代码未保存，则保存代码
            if (!CheckModifiedCode(true))
                return;

            // 重设参数
            Code = InitialCode;
            FileName = "Unnamed";
            FilePath = "";
            Modified = false;
        }

        /// <summary>
        /// 打开代码
        /// </summary>
        public void Open()
        {
            // 如果当前代码未保存，则保存代码
            if (!CheckModifiedCode(true))
                return;

            // 显示代码打开窗口
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "Text documents (.txt)|*.txt";
            openFileDialog.DefaultExt = ".txt";

            // 如果用户选择确认，那么载入相应的文件
            if (openFileDialog.ShowDialog() == true)
            {
                FilePath = openFileDialog.FileName;
                FileName = openFileDialog.SafeFileName;
                ui_editor.Load(m_filePath);
                Modified = false;
            }
        }

        /// <summary>
        /// 保存代码
        /// </summary>
        /// <returns>是否保存成功</returns>
        public bool Save()
        {
            // 判断是否已经保存过
            // 如果是，那么直接在上次保存的文件处保存
            // 否则调用另存为函数
            if (m_filePath != "")
            {
                try
                {
                    // 保存到对应文件
                    ui_editor.Save(m_filePath);
                    Modified = false;
                    return true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("FAILED TO SAVE FILE :\n" + ex.Message);
                    return false;
                }
            }
            else
            {
                return SaveAs();
            }
        }

        /// <summary>
        /// 另存为代码
        /// </summary>
        /// <returns>是否保存成功</returns>
        public bool SaveAs()
        {
            try
            {
                // 显示代码保存窗口
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.Filter = "Text documents (.txt)|*.txt";
                saveFileDialog.FileName = FileName;
                saveFileDialog.DefaultExt = ".txt";

                // 若用户选择确认，那么设置路径参数并重新调用保存函数
                if (saveFileDialog.ShowDialog() == true)
                {
                    FilePath = saveFileDialog.FileName;
                    FileName = saveFileDialog.SafeFileName;
                    return Save();
                }
                
                // 否则返回保存失败
                return false;
            }
            catch (Exception ex)
            {
                MessageBox.Show("FAILED TO SAVE FILE :\n" + ex.Message);
                return false;
            }
        }

        /// <summary>
        /// 代码打开回调函数
        /// </summary>
        private void CommandOpen_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            Open();
        }

        /// <summary>
        /// 代码保存回调函数
        /// </summary>
        private void CommandSave_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            Save();
        }

        /// <summary>
        /// 新建代码回调函数
        /// </summary>
        private void CommandNew_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            New();
        }

        #endregion

        #region Config

        private Config m_config = new Config();

        /// <summary>
        /// 编辑器配置文件
        /// </summary>
        public Config Configure
        {
            get { return m_config; }
            set { m_config = value; }
        }

        /// <summary>
        /// 默认配置
        /// </summary>
        public readonly Config defaultConfig = new Config();

        /// <summary>
        /// 根据配置文件更新界面
        /// </summary>
        public void UpdateConfig()
        {
            LoadConfig(m_config);
            InvalidateVisual();

            if (PauseLine != -1)
                PauseLine = PauseLine;
            if (ErrorLine != -1)
                ErrorLine = ErrorLine;
            if (m_stackLine != -1)
                StackCallLine(m_stackLine);

            if (foldingManager != null)
            {
                FoldingManager.Uninstall(foldingManager);
                foldingManager = FoldingManager.Install(ui_editor.TextArea);
                if (foldingStrategy != null)
                {
                    foldingStrategy.UpdateFoldings(foldingManager, ui_editor.Document);
                }
            }
            

            ui_editor.TextArea.TextView.InvalidateLayer(KnownLayer.Background);
            ui_editor.TextArea.TextView.InvalidateLayer(KnownLayer.Caret);
            ui_editor.TextArea.TextView.InvalidateLayer(KnownLayer.Selection);
            ui_editor.TextArea.TextView.InvalidateLayer(KnownLayer.Text);
        }

        /// <summary>
        /// 载入配置文件
        /// </summary>
        /// <param name="config">待载入的配置文件</param>
        private void LoadConfig(Config config)
        {
            // 生成语法高亮定义
            string xshdString = config.ToXshdString();
            TextReader tr = new StringReader(xshdString);
            XshdSyntaxDefinition syntaxDefinition;
            using (XmlTextReader reader = new XmlTextReader(tr))
            {
                syntaxDefinition = HighlightingLoader.LoadXshd(reader);
            }
            HighlightingManager manager = HighlightingManager.Instance;
            IHighlightingDefinition def = HighlightingLoader.Load(syntaxDefinition, manager);
            ui_editor.SyntaxHighlighting = def;

            // 设置编辑器字体
            ui_editor.FontFamily = new FontFamily(Configure.TextFont);
            ui_editor.FontSize = Configure.TextSize;
            ui_editor.FontStyle = Configure.TextStyle;
            ui_editor.FontWeight = Configure.TextWeight;
            ui_editor.Foreground = new SolidColorBrush(Configure.TextColor);

            // 设置背景颜色
            ui_editor.Background = new SolidColorBrush(Configure.BackGroundColor);
            // 设置各种高两行以及绘图元素的颜色
            m_caretLineRenderer.BgColor = Configure.CurrentLineColor;
            m_errorColor = Configure.ErrorLineColor;
            m_pauseColor = Configure.PauseLineColor;
            m_stackColor = Configure.StackLineColor;
            m_breakPointMargin.BreakPointBrush
                = new SolidColorBrush(Configure.BreakpointColor);
            m_breakPointMargin.PausingArrowBrush
                = new SolidColorBrush(Configure.PauseArrowColor);
            ui_editor.LineNumbersForeground
                = new SolidColorBrush(Configure.LineNumberColor);

            // 设置是否显示行号
            ui_editor.ShowLineNumbers = false;
            ui_editor.TextArea.LeftMargins.Clear();
            ui_editor.ShowLineNumbers = Configure.ShowLineNumber;
            ui_editor.TextArea.LeftMargins.Insert(0, m_breakPointMargin);
            // 设置缩进
            ui_editor.Options.IndentationSize = Configure.IndentionSize;
        }

        /// <summary>
        /// 配置文件
        /// </summary>
        public class Config
        {
            /// <summary>
            /// 构造函数，生成默认的配置
            /// </summary>
            public Config()
            {
                HighlightSettings.Add(cfg_Comment,
                    new Highlight(Colors.Gray, false, true));
                HighlightSettings.Add(cfg_String,
                    new Highlight(Colors.Red, false, false));
                HighlightSettings.Add(cfg_KeyWord,
                    new Highlight(Colors.Blue, true, false));
                HighlightSettings.Add(cfg_Function,
                    new Highlight(Colors.DarkCyan, true, false));
                HighlightSettings.Add(cfg_Digit,
                    new Highlight(Colors.Green, false, false));
            }

            #region Member Variable

            // 各种配置的键名
            public static readonly string cfg_Comment = "Comment";
            public static readonly string cfg_String = "String";
            public static readonly string cfg_KeyWord = "LogoScriptKeyWords";
            public static readonly string cfg_Function = "LogoScriptGlobalFunctions";
            public static readonly string cfg_Digit = "Digits";

            public static readonly string cfg_TextFont = "TextFont";
            public static readonly string cfg_TextSize = "TextSize";
            public static readonly string cfg_TextStyle = "TextStyle";
            public static readonly string cfg_TextWeight = "TextWeight";
            public static readonly string cfg_TextColor = "TextColor";

            /// <summary>
            /// 字体
            /// </summary>
            public string TextFont = "Consolas";

            /// <summary>
            /// 字号
            /// </summary>
            public double TextSize = 16;

            /// <summary>
            /// 斜体样式
            /// </summary>
            public FontStyle TextStyle = FontStyles.Normal;

            /// <summary>
            /// 粗体样式
            /// </summary>
            public FontWeight TextWeight = FontWeights.Normal;

            /// <summary>
            /// 颜色
            /// </summary>
            public Color TextColor = Colors.Black;

            public static readonly string cfg_BackGroundColor = "BackGroundColor";
            /// <summary>
            /// 背景颜色
            /// </summary>
            public Color BackGroundColor
                = Colors.White;

            public static readonly string cfg_CurrentLineColor = "CurrentLineColor";
            /// <summary>
            /// 当前行颜色
            /// </summary>
            public Color CurrentLineColor
                = Color.FromArgb(0x30, 0, 0, 0xFF);

            public static readonly string cfg_PauseArrowColor = "PauseArrowColor";
            /// <summary>
            /// 暂停箭头颜色
            /// </summary>
            public Color PauseArrowColor
                = Colors.Orange;

            public static readonly string cfg_PauseLineColor = "PauseLineColor";
            /// <summary>
            /// 暂停行颜色
            /// </summary>
            public Color PauseLineColor
                = Colors.Yellow;

            public static readonly string cfg_ErrorLineColor = "ErrorLineColor";
            /// <summary>
            /// 错误行颜色
            /// </summary>
            public Color ErrorLineColor
                = Color.FromArgb(0x70, 0xFF, 0, 0);

            public static readonly string cfg_LineNumberColor = "LineNumberColor";
            /// <summary>
            /// 行号颜色
            /// </summary>
            public Color LineNumberColor
                = Colors.DarkCyan;

            public static readonly string cfg_BreakpointColor = "BreakpointColor";
            /// <summary>
            /// 断点颜色
            /// </summary>
            public Color BreakpointColor
                = Colors.Red;

            public static readonly string cfg_StackLineColor = "StackLineColor";
            /// <summary>
            /// 堆栈行颜色
            /// </summary>
            public Color StackLineColor
                = Color.FromArgb(50, 0x00, 0xFF, 0x00);

            public static readonly string cfg_IndentionSize = "IndentionSize";
            /// <summary>
            /// 缩进大小
            /// </summary>
            public int IndentionSize = 4;

            public static readonly string cfg_ShowLineNumber = "ShowLineNumber";
            /// <summary>
            /// 是否显示行号
            /// </summary>
            public bool ShowLineNumber = true;

            #endregion

            #region Convert            

            /// <summary>
            /// 将0-255数字转换为字符串
            /// </summary>
            /// <param name="b">数字</param>
            /// <returns>数字对应的字符串</returns>
            /// <example>
            /// 以123为参数调用本函数，返回"7B"
            /// </example>
            private string ByteToString(byte b)
            {
                string ans = "";
                ans += NumToChar[b / 16];
                ans += NumToChar[b % 16];
                return ans;
            }

            /// <summary>
            /// 将颜色转换为字符串
            /// </summary>
            /// <param name="c">颜色</param>
            /// <returns>颜色对应的字符串</returns>
            /// <example>
            /// 以颜色 { R = 123, G = 100, B = 78 }调用本函数
            /// 返回"#7B644E"
            /// </example>
            private string ColorToString(Color c)
            {
                string str = "#" + ByteToString(c.A) +
                    ByteToString(c.R) + ByteToString(c.G) + ByteToString(c.B);
                return str;
            }
            
            /// <summary>
            /// 将高亮信息转换为字符串
            /// </summary>
            /// <param name="hl">高亮信息</param>
            /// <returns>转换后的字符串</returns>
            /// <example>
            /// 以高亮信息 { Color = { R = 123, G = 100, B = 78 }, Bold = true, Italic = false }
            /// 调用本函数，返回"#7B644E;bold;normal"
            /// </example>
            private string HighlightToString(Highlight hl)
            {
                string ans = ColorToString(hl.Color) + ";";
                ans += hl.Bold ? "bold;" : "normal;";
                ans += hl.Italic ? "italic" : "normal";
                return ans;
            }

            /// <summary>
            /// 将十六进制字符转换成数字
            /// </summary>
            /// <param name="c">字符</param>
            /// <returns>转换后的数字</returns>
            private int CharToInt(char c)
            {
                if ('0' <= c && c <= '9')
                    return c - '0';
                else if ('A' <= c && c <= 'F')
                    return c - 'A' + 10;
                else
                    return 0;
            }

            /// <summary>
            /// 将字符串转换为byte类型数字
            /// </summary>
            /// <param name="s">字符串</param>
            /// <param name="index">转换开始的位置</param>
            /// <returns>对应的数字，若转换失败则返回0</returns>
            /// <example>
            /// 以"#7B644E", 5为参数调用本函数，
            /// 返回78
            /// </example>
            private byte StringToByte(string s, int index)
            {
                try
                {
                    return (byte)(CharToInt(s[index]) * 16 + CharToInt(s[index + 1]));
                }
                catch { return 0; }
            }

            /// <summary>
            /// 将字符串转换为颜色
            /// </summary>
            /// <param name="s">字符串</param>
            /// <returns>转换后的颜色</returns>
            private Color StringToColor(string s)
            {
                byte r = 0, g = 0, b = 0, a = 0;
                a = StringToByte(s, 1);
                r = StringToByte(s, 3);
                g = StringToByte(s, 5);
                b = StringToByte(s, 7);
                return Color.FromArgb(a, r, g, b);
            }

            /// <summary>
            /// 将字符串转换为高亮信息
            /// <see cref="HighlightToString"/>的反函数
            /// </summary>
            /// <param name="s">字符串</param>
            /// <returns>对应的高亮信息，若转换失败，返回黑色普通配置</returns>
            private Highlight StringToHighlight(string s)
            {
                string[] split = s.Split(';');
                try
                {
                    Highlight hl = new Highlight();
                    hl.Color = StringToColor(split[0]);
                    hl.Bold = (split[1].ToLower() == "bold");
                    hl.Italic = (split[2].ToLower() == "italic");
                    return hl;
                }
                catch { return new Highlight(Colors.Black, false, false); }
            }

            #endregion

            #region Xshd Builder

            /// <summary>
            /// 高亮信息
            /// </summary>
            public struct Highlight
            {
                /// <summary>
                /// 构造函数
                /// </summary>
                /// <param name="c">高亮颜色</param>
                /// <param name="bold">是否粗体</param>
                /// <param name="italic">是否斜体</param>
                public Highlight(Color c, bool bold, bool italic)
                {
                    Color = c;
                    Bold = bold;
                    Italic = italic;
                }

                /// <summary>
                /// 高亮颜色
                /// </summary>
                public bool Bold;

                /// <summary>
                /// 是否粗体
                /// </summary>
                public bool Italic;

                /// <summary>
                /// 是否斜体
                /// </summary>
                public Color Color;
            }

            /// <summary>
            /// 高亮设置词典
            /// 键为高亮类型，值为对应的高亮设置
            /// </summary>
            public Dictionary<string, Highlight> HighlightSettings
                = new Dictionary<string, Highlight>();

            /// <summary>
            /// 高亮关键词列表
            /// </summary>
            public HashSet<string> KeyWords
                = new HashSet<string>(new string[] { "function", "while", "if", "else", "return", "break", "continue", "local", "for" });

            /// <summary>
            /// 高亮系统函数列表
            /// </summary>
            public HashSet<string> KeyFunctions
                = new HashSet<string>();

            /// <summary>
            /// 十六进制数字到字符映射表
            /// </summary>
            private static readonly char[] NumToChar = new char[] {
                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                'A', 'B', 'C', 'D', 'E', 'F'
            };

            /// <summary>
            /// 将高亮设置转换为Xml语法格式（该语法格式由AvalonEdit解析）
            /// </summary>
            /// <returns>对应的Xml字符串</returns>
            public string ToXshdString()
            {
                StringBuilder sb = new StringBuilder(65536);

                sb.AppendLine("<?xml version=\"1.0\"?>");
                sb.AppendLine("<SyntaxDefinition name=\"LogoScript\" extensions=\".ls\" xmlns=\"http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008\">");

                // 生成高亮设置信息
                foreach (var setting in HighlightSettings)
                {
                    sb.Append("<Color name=\"");
                    sb.Append(setting.Key);
                    sb.Append("\" foreground=\"");
                    sb.Append(ColorToString(setting.Value.Color));
                    sb.Append("\"");

                    if (setting.Value.Bold)
                        sb.Append(" fontWeight=\"bold\"");
                    if (setting.Value.Italic)
                        sb.Append(" fontStyle=\"italic\"");

                    sb.AppendLine(" />");
                }

                sb.AppendLine("<RuleSet ignoreCase=\"false\">");

                // 设置关键词高亮
                sb.AppendLine(string.Format("<Keywords color=\"{0}\">", cfg_KeyWord));
                foreach (var word in KeyWords)
                    sb.AppendLine(string.Format("<Word>{0}</Word>", word));
                sb.AppendLine("</Keywords>");

                // 设置系统函数高亮
                sb.AppendLine(string.Format("<Keywords color=\"{0}\">", cfg_Function));
                foreach (var word in KeyFunctions)
                    sb.AppendLine(string.Format("<Word>{0}</Word>", word));
                sb.AppendLine("</Keywords>");

                // 注释高亮
                sb.AppendLine(string.Format("<Span color=\"{0}\">", cfg_Comment));
                sb.AppendLine("<Begin>`</Begin>");
                sb.AppendLine("</Span>");

                // 字符串高亮
                sb.AppendLine(string.Format("<Span color=\"{0}\" multiline=\"true\">", cfg_String));
			    sb.AppendLine("<Begin>\"</Begin>");
			    sb.AppendLine("<End>\"</End>");
			    sb.AppendLine("<RuleSet>");
				sb.AppendLine("<Span begin=\"\\\\\" end=\".\" />");
			    sb.AppendLine("</RuleSet>");
                sb.AppendLine("</Span>");

                // 数值高亮
                sb.AppendLine(string.Format("<Rule color=\"{0}\">", cfg_Digit));
			    sb.AppendLine("\\b\\d+(\\.[0-9]*)?|\\.[0-9]*");
		        sb.AppendLine("</Rule>");

                sb.AppendLine("</RuleSet>");
                sb.AppendLine("</SyntaxDefinition>");

                return sb.ToString();
            }

            #endregion

            #region Save/Load

            /// <summary>
            /// 保存编辑器配置
            /// </summary>
            /// <param name="tw">输出器</param>
            public void Save(TextWriter tw)
            {
                // 新建配置文件并将当前信息设置到配置文件中
                LogoScriptIDE.Config cfg = new LogoScriptIDE.Config();
                
                cfg.SetField(cfg_Comment, HighlightToString(HighlightSettings[cfg_Comment]));
                cfg.SetField(cfg_String, HighlightToString(HighlightSettings[cfg_String]));
                cfg.SetField(cfg_KeyWord, HighlightToString(HighlightSettings[cfg_KeyWord]));
                cfg.SetField(cfg_Function, HighlightToString(HighlightSettings[cfg_Function]));
                cfg.SetField(cfg_Digit, HighlightToString(HighlightSettings[cfg_Digit]));

                cfg.SetField(cfg_TextFont, TextFont);
                cfg.SetField(cfg_TextSize, TextSize.ToString());
                cfg.SetField(cfg_TextStyle, TextStyle == FontStyles.Italic ? "italic" : "normal");
                cfg.SetField(cfg_TextWeight, TextWeight == FontWeights.Bold ? "bold" : "normal");
                cfg.SetField(cfg_TextColor, ColorToString(TextColor));

                cfg.SetField(cfg_BackGroundColor, ColorToString(BackGroundColor));
                cfg.SetField(cfg_CurrentLineColor,ColorToString(CurrentLineColor));
                cfg.SetField(cfg_PauseArrowColor,ColorToString(PauseArrowColor));
                cfg.SetField(cfg_PauseLineColor,ColorToString(PauseLineColor));
                cfg.SetField(cfg_ErrorLineColor,ColorToString(ErrorLineColor));
                cfg.SetField(cfg_LineNumberColor,ColorToString(LineNumberColor));
                cfg.SetField(cfg_BreakpointColor, ColorToString(BreakpointColor));
                cfg.SetField(cfg_StackLineColor, ColorToString(StackLineColor));

                cfg.SetField(cfg_IndentionSize, IndentionSize.ToString());
                cfg.SetField(cfg_ShowLineNumber, ShowLineNumber ? "true" : "false");

                // 保存配置文件
                cfg.Save(tw);
            }

            /// <summary>
            /// 载入编辑器配置
            /// </summary>
            /// <param name="tr">读取器</param>
            public void Load(TextReader tr)
            {
                LogoScriptIDE.Config cfg = new LogoScriptIDE.Config();
                cfg.Load(tr);

                // 设置语法高亮配置
                HighlightSettings[cfg_Comment] = StringToHighlight(cfg.GetField(cfg_Comment));
                HighlightSettings[cfg_String] = StringToHighlight(cfg.GetField(cfg_String));
                HighlightSettings[cfg_KeyWord] = StringToHighlight(cfg.GetField(cfg_KeyWord));
                HighlightSettings[cfg_Function] = StringToHighlight(cfg.GetField(cfg_Function));
                HighlightSettings[cfg_Digit] = StringToHighlight(cfg.GetField(cfg_Digit));

                // 设置字体
                TextFont = cfg.GetField(cfg_TextFont);
                try { TextSize = Int32.Parse(cfg.GetField(cfg_TextSize)); }
                catch { TextSize = 16; }
                if (TextSize < 9 || TextSize > 100) TextSize = 16;
                TextStyle = (cfg.GetField(cfg_TextStyle).ToLower() == "italic" ?
                    FontStyles.Italic : FontStyles.Normal);
                TextWeight = (cfg.GetField(cfg_TextWeight).ToLower() == "bold" ?
                    FontWeights.Bold : FontWeights.Normal);
                TextColor = StringToColor(cfg.GetField(cfg_TextColor));

                // 设置颜色
                BackGroundColor = StringToColor(cfg.GetField(cfg_BackGroundColor));
                CurrentLineColor = StringToColor(cfg.GetField(cfg_CurrentLineColor));
                PauseArrowColor = StringToColor(cfg.GetField(cfg_PauseArrowColor));
                PauseLineColor = StringToColor(cfg.GetField(cfg_PauseLineColor));
                ErrorLineColor = StringToColor(cfg.GetField(cfg_ErrorLineColor));
                LineNumberColor = StringToColor(cfg.GetField(cfg_LineNumberColor));
                BreakpointColor = StringToColor(cfg.GetField(cfg_BreakpointColor));
                StackLineColor = StringToColor(cfg.GetField(cfg_StackLineColor));

                try { IndentionSize = Int32.Parse(cfg.GetField(cfg_IndentionSize)); }
                catch { IndentionSize = 4; }
                if (IndentionSize < 1 || IndentionSize > 8) IndentionSize = 4;
                ShowLineNumber = (cfg.GetField(cfg_ShowLineNumber).ToLower() == "true" ? true : false);
            }

            #endregion
        }

        #endregion

        /// <summary>
        /// 窗口关闭回调函数
        /// </summary>
        public void Window_Closed()
        {
            // 将配置信息写入到文件中，自动保存
            try
            {
                using (StreamWriter sr = new StreamWriter(ConfigPath))
                    Configure.Save(sr);
            }
            catch { }
        }

        #region Context Menu

        /// <summary>
        /// 右键菜单复制按钮回调函数
        /// </summary>
        private void ui_mnuCopy_Click(object sender, RoutedEventArgs e)
        {
            Copy();
        }

        /// <summary>
        /// 右键菜单剪切按钮回调函数
        /// </summary>
        private void ui_mnuCut_Click(object sender, RoutedEventArgs e)
        {
            Cut();
        }

        /// <summary>
        /// 右键菜单粘贴按钮回调函数
        /// </summary>
        private void ui_mnuPaste_Click(object sender, RoutedEventArgs e)
        {
            Paste();
        }

        /// <summary>
        /// 右键菜单清空所有断点按钮回调函数
        /// </summary>
        private void ui_mnuClearBreakpoints_Click(object sender, RoutedEventArgs e)
        {
            RemoveBreakpoints();
        }

        /// <summary>
        /// 右键菜单注释代码按钮回调函数
        /// </summary>
        private void ui_mnuComment_Click(object sender, RoutedEventArgs e)
        {
            Comment();
        }

        /// <summary>
        /// 右键菜单取消注释代码按钮回调函数
        /// </summary>
        private void ui_mnuUncomment_Click(object sender, RoutedEventArgs e)
        {
            Uncomment();
        }

        /// <summary>
        /// 右键打开事件回调函数
        /// </summary>
        private void Window_ContextMenuOpening(object sender, ContextMenuEventArgs e)
        {
            // 根据当前编辑器是否只读来判定右键菜单按钮是否可点击
            if (ui_editor.IsReadOnly)
            {
                ui_mnuComment.IsEnabled = false;
                ui_mnuUncomment.IsEnabled = false;
                ui_mnuCut.IsEnabled = false;
                ui_mnuPaste.IsEnabled = false;
            }
            else
            {
                ui_mnuComment.IsEnabled = true;
                ui_mnuUncomment.IsEnabled = true;
                ui_mnuCut.IsEnabled = true;
                ui_mnuPaste.IsEnabled = true;
            }
        }

        #endregion

        #region Timer(Syntax check & folding)
        
        /// <summary>
        /// 代码折叠器管理器
        /// </summary>
        private FoldingManager foldingManager = null;

        /// <summary>
        /// 代码折叠器
        /// </summary>
        private AbstractFoldingStrategy foldingStrategy = null;

        /// <summary>
        /// 时钟回调函数
        /// 进行动态语法检查和折叠检查
        /// </summary>
        private void TimerTick(object sender, EventArgs e)
        {
            if (!ui_editor.IsVisible) return;
            // 装载代码折叠器
            if (foldingStrategy != null)
            {
                foldingStrategy.UpdateFoldings(foldingManager, ui_editor.Document);
            }

            if (ui_editor.IsReadOnly) return;

            Machine m;
            int errorLine = -1;

            // 尝试编译代码，若编译失败则找出错误的代码行
            m = new Machine();
            try
            {
                m.Compile(new StringStream(Code));
            }
            catch (CompileException ex)
            {
                errorLine = ex.Line;
            }
            catch (Exception) { }

            var curLine = ui_editor.Document.GetLineByOffset(ui_editor.CaretOffset);
            int caretLineNum = curLine.LineNumber;

            // 若没有错误，则不标记错误行
            if (errorLine == -1)
            {
                ErrorLine = -1;
                return;
            }

            // 若存在错误，并且错误不在当前行，或错误在当前行或当前行下一行但用户已停留超过2秒
            // 则标记错误行
            if ((caretLineNum == errorLine || caretLineNum + 1 == errorLine) &&
                (DateTime.Now - m_lastModifyTime).TotalSeconds < 2)
            {
                ErrorLine = -1;
            }
            else
            {
                ErrorLine = errorLine;
            }
        }

        #endregion

        #region Find & Replace

        /// <summary>
        /// 查找下一个
        /// </summary>
        /// <param name="text">待查找的字符串</param>
        /// <param name="caseSensitive">是否大小写敏感</param>
        public void FindNext(string text, bool caseSensitive)
        {
            int startIndex = ui_editor.CaretOffset;
            int findIndex = Code.IndexOf(
                text, startIndex, GetComparison(caseSensitive));
            Find(text, findIndex);
        }

        /// <summary>
        /// 查找上一个
        /// </summary>
        /// <param name="text">待查找的字符串</param>
        /// <param name="caseSensitive">是否大小写敏感</param>
        public void FindPrevious(string text, bool caseSensitive)
        {
            int startIndex = ui_editor.CaretOffset;
            int findIndex;
            if (startIndex >= text.Length)
            {
                findIndex = Code.LastIndexOf(
                    text, startIndex - text.Length, GetComparison(caseSensitive));
            }
            else
            {
                findIndex = -1;
            }
            Find(text, findIndex);
            if (findIndex != -1)
                ui_editor.CaretOffset = findIndex;
        }

        /// <summary>
        /// 替换选中段
        /// </summary>
        /// <param name="from">被替换的字符串</param>
        /// <param name="to">用来替换的字符串</param>
        /// <param name="caseSensitive">是否大小写敏感</param>
        public void Replace(string from, string to, bool caseSensitive)
        {
            // 是否只读，若只读则拒绝操作
            if (ui_editor.IsReadOnly)
                return;

            bool equal;

            // 根据是否大小写敏感来判断选中段是否是被替换的字符串
            if (caseSensitive)
                equal = (ui_editor.SelectedText == from);
            else
                equal = (ui_editor.SelectedText.ToLowerInvariant() ==
                    from.ToLowerInvariant());

            // 如果选中了被替换的字符串则进行替换
            // 否则先找到需要被替换的字符串
            if (equal)
                ui_editor.SelectedText = to;
            FindNext(from, caseSensitive);
        }

        /// <summary>
        /// 替换所有字符串
        /// </summary>
        /// <param name="from">待替换的字符串</param>
        /// <param name="to">用于替换的字符串</param>
        /// <param name="caseSensitive">是否大小写敏感</param>
        public void ReplaceAll(string from, string to, bool caseSensitive)
        {
            if (ui_editor.IsReadOnly)
                return;

            int startIndex = 0;
            int count = 0;
            while (true)
            {
                // 找下一个待替换的字符串位置
                int findIndex = Code.IndexOf(
                    from, startIndex, GetComparison(caseSensitive));

                // 已找完，退出循环
                if (findIndex < 0)
                    break;

                // 选中待替换的字符串并进行替换
                ui_editor.Select(findIndex, from.Length);
                ui_editor.SelectedText = to;

                // 移动查找坐标，避免死循环（如把a替换成a）
                startIndex = findIndex + to.Length;
                ++count;
            }
            
            MessageBox.Show(String.Format("{0} strings were replaced.", count));
        }

        /// <summary>
        /// 根据是否大小写敏感获得字符串比较参数
        /// </summary>
        /// <param name="caseSensitive">是否大小写敏感</param>
        /// <returns>对应的字符串比较参数</returns>
        private StringComparison GetComparison(bool caseSensitive)
        {
            return caseSensitive ? 
                StringComparison.CurrentCulture : 
                StringComparison.CurrentCultureIgnoreCase;
        }

        /// <summary>
        /// 选中字符串
        /// </summary>
        /// <param name="text">字符串</param>
        /// <param name="findIndex">字符串位置</param>
        private void Find(string text, int findIndex)
        {
            
            if (findIndex < 0)
            {
                MessageBox.Show("No match was found.");
            }
            else
            {
                ui_editor.Select(findIndex, text.Length);
                // 编辑器移动到对应行
                int lineNumber =
                    ui_editor.Document.GetLineByOffset(findIndex).LineNumber;
                ui_editor.ScrollToLine(lineNumber);
            }
        }

        #endregion

    }
}
